#!/usr/bin/env python3
#coding=utf-8
# => Author: Abby Cin
# => Mail: abbytsing@gmail.com
# => Created Time: Thu 18 May 2017 09:06:20 AM CST

import socket
import json
import time


class PacketBlock(object):
    PROTOCOL_PACKET_HEAD_LENGTH = 4
    PROTOCOL_PACKET_CONSISTENT_LENGTH = 11 + PROTOCOL_PACKET_HEAD_LENGTH
    PROTOCOL_STANDARD_HEAD_DATA = [0xEF,0x02,0xAA,0xAA]

    def __init__(self):
        self.head = [0] * self.PROTOCOL_PACKET_HEAD_LENGTH
        self.targetAddress = 0
        self.sourceAddress = 0
        self.targetAddressBytes = [0] * 2
        self.sourceAddressBytes = [0] * 2
        self.index = 0
        self.indexBytes = [0] * 2
        self.functionWord = 0
        self.headCheckSum = 0
        self.messageDataLength = 0
        self.messageDataLengthBytes = [0] * 2
        self.messageData = []
        self.messageDataCheckSum = 0

    def CalculatePacketBlockHeadCheckSum(self):
        headCheckSum = sum(self.head)
        headCheckSum += sum(self.targetAddressBytes)
        headCheckSum += sum(self.sourceAddressBytes)
        headCheckSum += sum(self.indexBytes)
        headCheckSum += self.functionWord
        headCheckSum += sum(self.messageDataLengthBytes)
        res = headCheckSum % (0x100)       #相当于只取最低位
        return res;

    def CalculatePacketBlockMessageDataCheckSum(self):
        messageDataCheckSum = sum(self.messageData)
        return messageDataCheckSum % (0x100)#相当于只取最低位

class AssembleCommunicationProtocolPacket(object):
    Protocol_HeadData = PacketBlock.PROTOCOL_STANDARD_HEAD_DATA[:]
    Protocol_PacketSendIndex = 0
    Protocol_LocalhostAddress = 0x0001
    FunctionWord_TypeDef = {
            'FunctionWord_Null': 0,
            'FunctionWord_Handshake': 0xF0,
            'FunctionWord_Acknowledgement': 0xF1,
            'FunctionWord_RegisterDevice': 0xF2,
            'FunctionWord_Dormant': 0xF3,
            'FunctionWord_StartUP': 0xF4,
            'FunctionWord_Data': 0xF5,
            'FunctionWord_SetProperty': 0xF6,
            'FunctionWord_Logout': 0xF7,
            'FunctionWord_Reboot': 0xF8,
            'FunctionWord_Shutdown': 0xF9
            }
    def __init__(self):
        pass

    def int_to_list(self, int_data, bytes_length):
        bytes_list = bytearray(int_data.to_bytes(bytes_length, byteorder='little'))
        return bytes_list

    def assemble_protocol_packet_block(self,target_address, source_address, function_word, message_data):
        packet_block = PacketBlock()
        message_data_length = len(message_data)
        packet_block.head = AssembleCommunicationProtocolPacket.Protocol_HeadData[:]
        packet_block.targetAddress = target_address
        packet_block.targetAddressBytes = self.int_to_list(target_address, len(packet_block.targetAddressBytes))
        packet_block.sourceAddress = source_address
        packet_block.sourceAddressBytes = self.int_to_list(source_address, len(packet_block.sourceAddressBytes))
        packet_block.index = AssembleCommunicationProtocolPacket.Protocol_PacketSendIndex
        packet_block.indexBytes = self.int_to_list(packet_block.index, len(packet_block.indexBytes))
        packet_block.functionWord = function_word
        packet_block.messageDataLength = message_data_length
        packet_block.messageDataLengthBytes = self.int_to_list(message_data_length, len(packet_block.messageDataLengthBytes))
        packet_block.headCheckSum = packet_block.CalculatePacketBlockHeadCheckSum()
        packet_block.messageData = bytearray(message_data)
        packet_block.messageDataCheckSum = packet_block.CalculatePacketBlockMessageDataCheckSum()
        AssembleCommunicationProtocolPacket.Protocol_PacketSendIndex += 1
        return packet_block

    def resolve_packet_struct_into_bytes(self, packet_block):
        bytes_offset = 0
        protocol_packet_length = packet_block.messageDataLength + packet_block.PROTOCOL_PACKET_CONSISTENT_LENGTH
        assembled_packet_bytes = bytearray(protocol_packet_length)
        subject = [
                packet_block.head,
                packet_block.targetAddressBytes,
                packet_block.sourceAddressBytes,
                packet_block.indexBytes,
                [packet_block.functionWord],
                packet_block.messageDataLengthBytes,
                [packet_block.headCheckSum],
                packet_block.messageData,
                [packet_block.messageDataCheckSum],
                ]

        for item in subject:
            bytes_length = len(item)
            assembled_packet_bytes[bytes_offset:bytes_offset + bytes_length] = bytearray(item)
            bytes_offset += bytes_length

        return assembled_packet_bytes

if __name__ == '__main__':
    message = {
            "InfoType": "Data",
            "Owner": "admin",
            "Address": 2,
            "Temperature": 28,
            "Humidity": 42,
            "Noise": 48.799999,
            "PM2_5": 26.200001,
            "PM10": 27.600000,
            "WindDirection": 228,
            "WindSpeed": 0
            }
    msg_data = json.dumps(message).encode()
    pkg = AssembleCommunicationProtocolPacket()
    pkg_blk = pkg.assemble_protocol_packet_block(0x002, 0x001, pkg.FunctionWord_TypeDef['FunctionWord_Data'], msg_data)
    data = pkg.resolve_packet_struct_into_bytes(pkg_blk)
    fd = socket.socket()
    fd.connect(("127.0.0.1", 31511))
    for i in range(0, 10):
        print("send data ", i + 1)
        fd.send(data)
        time.sleep(2)
